datatype lexresult=   SHELL of string * string * {line: word, column: word};

val error = fn x => TextIO.output(TextIO.stdOut,x ^ "\n")
val eof = fn () => SHELL("","eof",getNextTokenPos(""))

(* ------------------------------------------------------------------ *)
(* assumes that ">" does not occur as part of a nonterminal symbol *)
fun generateSchemaTokenName( yytext ) =
    let
		fun split(x, []   ) =  raise General.Fail("an_error")
		  | split(x, y::ys) = if x=y then ys else split(x,ys);
													
		fun splitFirst(symbol,[])    = 	[] (* symbol was not in the input list *)
		  | splitFirst(symbol,x::xs) = 	if x = symbol 
										then (* found split point *)
											[]
										else (* keep looking      *)
											x::splitFirst(symbol,xs);
																		
        val s0   = explode(yytext);
        val s1   = split(#"<",s0);
        val s2   = splitFirst(#">",s1);  
    in
        implode(explode("!#schema_variable_") @ s2)        
    end;
	
(* ------------------------------------------------------------------ *)
%%
%header (functor Target_LexFn(val getNextTokenPos : string -> {line: word, column: word}));

alpha        = [A-Za-z];
symbol       = [<];
digit        = [0-9];
alphanumeric = [A-Za-z0-9_'];
identifier   = {alpha}{alphanumeric}*;
string       = \"{alphanumeric}*\";
symbolic_id  = {symbol}+{alphanumeric}*;
number       = {digit}+(\.{digit}+)?;
schema_id    = "<" {alpha}{alphanumeric}* ">_" {alphanumeric}+;
comment      = "(*" .* "*)";
comment1     = "/*" .* "*/";
comment2     = "//" .*;
ws           = [\  \t \n];
%%
{ws}+        => ( getNextTokenPos(yytext); lex()  );
{schema_id}  => ( SHELL(generateSchemaTokenName(yytext) , yytext, getNextTokenPos(yytext)) );
{comment}    => ( getNextTokenPos(yytext); lex()  );
{comment1}   => ( getNextTokenPos(yytext); lex()  );
{comment2}   => ( getNextTokenPos(yytext); lex()  );
"[:]"        => ( SHELL(""              , yytext, getNextTokenPos(yytext)) );
"{"          => ( SHELL(yytext          , yytext,     getNextTokenPos(yytext))  );
"}"          => ( SHELL(yytext          , yytext,     getNextTokenPos(yytext))  );
"("          => ( SHELL(yytext          , yytext,     getNextTokenPos(yytext))  );
")"          => ( SHELL(yytext          , yytext,     getNextTokenPos(yytext))  );
"+"          => ( SHELL(yytext          , yytext,     getNextTokenPos(yytext))  );
"-"          => ( SHELL(yytext          , yytext,     getNextTokenPos(yytext))  );
"~"          => ( SHELL(yytext          , yytext,     getNextTokenPos(yytext))  );
"*"          => ( SHELL(yytext          , yytext,     getNextTokenPos(yytext))  );
"/"          => ( SHELL(yytext          , yytext,     getNextTokenPos(yytext))  );
"="          => ( SHELL(yytext          , yytext,     getNextTokenPos(yytext))  );
"<"          => ( SHELL(yytext          , yytext,     getNextTokenPos(yytext))  );
">"          => ( SHELL(yytext          , yytext,     getNextTokenPos(yytext))  );
"<="         => ( SHELL(yytext          , yytext,     getNextTokenPos(yytext))  );
">="         => ( SHELL(yytext          , yytext,     getNextTokenPos(yytext))  );
"=>"         => ( SHELL(yytext          , yytext,     getNextTokenPos(yytext))  );
";"          => ( SHELL(yytext          , yytext,     getNextTokenPos(yytext))  );
"%"          => ( SHELL(yytext          , yytext,     getNextTokenPos(yytext))  );
"SKIP"       => ( SHELL(yytext          , yytext,     getNextTokenPos(yytext))  );
"ABORT"      => ( SHELL(yytext          , yytext,     getNextTokenPos(yytext))  );
"if"         => ( SHELL(yytext          , yytext,     getNextTokenPos(yytext))  );
"then"       => ( SHELL(yytext          , yytext,     getNextTokenPos(yytext))  );
"else"       => ( SHELL(yytext          , yytext,     getNextTokenPos(yytext))  );
"true"       => ( SHELL("boolean_value" , yytext,     getNextTokenPos(yytext))  );
"false"      => ( SHELL("boolean_value" , yytext,     getNextTokenPos(yytext))  );
"and"        => ( SHELL(yytext          , yytext,     getNextTokenPos(yytext))  );
"or"         => ( SHELL(yytext          , yytext,     getNextTokenPos(yytext))  );
"not"        => ( SHELL(yytext          , yytext,     getNextTokenPos(yytext))  );
"int"        => ( SHELL(yytext          , yytext,     getNextTokenPos(yytext))  );
"bool"       => ( SHELL(yytext          , yytext,     getNextTokenPos(yytext))  );

{identifier} 			=> ( SHELL("ident", 		yytext, getNextTokenPos(yytext))  );
"~"? {digit}+  			=> ( SHELL("integer_value",	yytext, getNextTokenPos(yytext))  );
{digit}*"."{digit}+ 		=> ( SHELL("real_value", 	yytext, getNextTokenPos(yytext))  );
"\"" ([^\"\\] | \\. )* "\""  	=> ( SHELL("string_value",	yytext, getNextTokenPos(yytext))  );
